package com.santoker.user.service.service.biz.auth.impl;

import com.santoker.baseservice.ApiResponseBody;
import com.santoker.baseservice.ApiResponseCode;
import com.santoker.baseservice.enums.AccountTypeEnum;
import com.santoker.baseservice.redis.AuthInfo;
import com.santoker.baseservice.util.BCrypt;
import com.santoker.baseservice.util.DateUtils;
import com.santoker.baseservice.util.FileUtil;
import com.santoker.user.service.config.ConfigProperty;
import com.santoker.user.service.dto.vo.auth.*;
import com.santoker.user.service.dto.vo.user.UserInfoModifyVo;
import com.santoker.user.service.exception.CommonServiceException;
import com.santoker.user.service.model.User;
import com.santoker.user.service.model.Version;
import com.santoker.user.service.service.biz.auth.AuthService;
import com.santoker.user.service.service.common.IUserService;
import com.santoker.user.service.service.common.IVersionService;
import com.santoker.user.service.service.common.RedisService;
import com.santoker.user.service.service.tp.wechat.WeChatApi;
import com.santoker.user.service.service.tp.wechat.response.WeChatAppAccessTokenResponse;
import com.santoker.user.service.service.tp.wechat.response.WeChatAppUserInfoResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;

@Slf4j
@Service
public class AuthServiceImpl extends AuthBaseServiceImpl implements AuthService {

    @Autowired
    private IUserService iUserService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ConfigProperty configProperty;
    @Autowired
    private WeChatApi weChatApi;
    @Autowired
    private IVersionService versionService;

    @Override
    @Transactional
    public RegisterResponseVo register(RegisterVo body) {

        log.info("------------------------------ 手机号注册  ------------------------------");
        ApiResponseBody.printRequestParam(body);

        // 验证手机号是否已注册
        User userByAccount = iUserService.getUserByAccount(body.getMobile());
        if (Objects.nonNull(userByAccount)) {
            throw new CommonServiceException(ApiResponseCode.REGISTER_DUPLICATED_PHONE);
        }

        // 验证验证码
        if (!redisService.verifyCode(body.getMobile(), body.getCaptcha())) {
            throw new CommonServiceException(ApiResponseCode.CAPTCHA_WRONG);
        }

        // 注册新用户
        User user = registerNewUser(body.getMobile(), body.getPassword(), body.getMobile(), "", "",
                body.getNickname(), null, null);

        RegisterResponseVo registerResponseVo = RegisterResponseVo.builder()
                .id(user.getId())
                .account(user.getAccount())
                .nickName(user.getNickname())
                .build();
        return registerResponseVo;
    }

    @Override
    @Transactional
    public RegisterResponseVo emailRegister(EmailRegisterVo body) {

        log.info("------------------------------ 邮箱注册  ------------------------------");
        ApiResponseBody.printRequestParam(body);

        // 验证邮箱是否已注册
        User userByEmail = iUserService.getUserByEmail(body.getEmail());
        if (Objects.nonNull(userByEmail)) {
            throw new CommonServiceException(ApiResponseCode.REGISTER_DUPLICATED_EMAIL);
        }

        // 验证验证码
        if (!redisService.verifyCode(body.getEmail(), body.getCaptcha())) {
            throw new CommonServiceException(ApiResponseCode.CAPTCHA_WRONG);
        }

        // 注册新用户
        User user = registerNewUser(body.getEmail(), body.getPassword(), "", body.getEmail(), "",
                body.getNickname(), null, null);

        RegisterResponseVo registerResponseVo = RegisterResponseVo.builder()
                .id(user.getId())
                .account(user.getAccount())
                .nickName(user.getNickname())
                .build();
        return registerResponseVo;
    }

    @Override
    public LoginResponseVo mobileLogin(LoginVo body) {

        log.info("------------------------------ 手机号登录  ------------------------------");
        ApiResponseBody.printRequestParam(body);

        // 验证手机号是否存在
        User user = iUserService.getUserByMobile(body.getAccount());
        if (Objects.isNull(user)) {
            throw new CommonServiceException(ApiResponseCode.MOBILE_NOT_EXIST);
        }

        // 校验密码是否匹配
        if (!verifyPassword(user.getPassword(), body.getPassword())) {
            throw new CommonServiceException(ApiResponseCode.PASSWORD_WRONG);
        }

        return getLoginResponse(user, body.getSid(), body.getCid());
    }

    @Override
    public LoginResponseVo emailLogin(LoginVo body) {

        log.info("------------------------------ 邮箱登录  ------------------------------");
        ApiResponseBody.printRequestParam(body);

        // 验证邮箱是否存在
        User user = iUserService.getUserByEmail(body.getAccount());
        if (Objects.isNull(user)) {
            throw new CommonServiceException(ApiResponseCode.EMAIL_NOT_EXIST);
        }

        // 校验密码是否匹配
        if (!verifyPassword(user.getPassword(), body.getPassword())) {
            throw new CommonServiceException(ApiResponseCode.PASSWORD_WRONG);
        }

        // 获取登录信息
        return getLoginResponse(user, body.getSid(), body.getCid());
    }

    @Override
    @Transactional
    public void resetPassword(ResetVo body) {

        log.info("------------------------------ 重置密码  ------------------------------");
        ApiResponseBody.printRequestParam(body);

        // 验证用户是否存在
        User user = iUserService.getUserByAccount(body.getAccount());
        if (Objects.isNull(user)) {
            throw new CommonServiceException(ApiResponseCode.ACCOUNT_NOT_EXIST);
        }

        // 验证验证码
        if (!redisService.verifyCode(body.getAccount(), body.getCaptcha())) {
            throw new CommonServiceException(ApiResponseCode.CAPTCHA_WRONG);
        }

        // 生成密码盐、密码加密
        String hashPassword = BCrypt.hashpw(body.getPassword(), BCrypt.gensalt());

        // 更新用户信息
        user.setUpdatedAt(DateUtils.getSecondTimestamp());
        user.setPassword(hashPassword);
        if (!iUserService.updateById(user)) {
            throw new CommonServiceException(ApiResponseCode.RESET_PASSWORD_FAILED);
        }
    }

    @Override
    @Transactional
    public void modifyUser(Integer userId, UserInfoModifyVo body) {

        log.info("------------------------------ 修改用户信息  ------------------------------");
        ApiResponseBody.printRequestParam(userId, body);

        // 验证用户是否存在
        User user = iUserService.getById(userId);
        if (Objects.isNull(user)) {
            throw new CommonServiceException(ApiResponseCode.USER_NOT_EXIST);
        }

        // 修改用户昵称：新昵称不为空，且新昵称与旧昵称不一致时更新
        if (StringUtils.isNotBlank(body.getNickname()) && !Objects.equals(body.getNickname(), user.getNickname())) {
            user.setNickname(body.getNickname());
        }

        // 更新用户头像
        if (StringUtils.isNotBlank(body.getAvatar())) {
            String avatar = FileUtil.getNoDomainUrl(body.getAvatar(), configProperty.fileDomain);
            user.setAvatar(avatar);
        }

        // 更新用户信息
        user.setUpdatedAt(DateUtils.getSecondTimestamp());
        if (!iUserService.updateById(user)) {
            throw new CommonServiceException(ApiResponseCode.USER_UPDATE_FAILURE);
        }
    }

    @Override
    public void logout(AuthInfo authInfo) {

        log.info("------------------------------ 登出  ------------------------------");
        ApiResponseBody.printRequestParam(authInfo);

        redisService.removeToken(authInfo);
    }

    @Override
    @Transactional
    public LoginResponseVo wxLogin(WxLoginVo body) {

        log.info("------------------------------ 微信授权登录（已作废）  ------------------------------");
        ApiResponseBody.printRequestParam(body);

        // 获取授权授权信息
        WeChatAppAccessTokenResponse accessToken = weChatApi.getAccessToken(body.getCode());
        if (!accessToken.isSuccess()) {
            throw new CommonServiceException(ApiResponseCode.WECHAT_AUTH_FAILURE);
        }

        // 获取微信用户信息
        WeChatAppUserInfoResponse userInfo = weChatApi.getUserInfo(accessToken.getAccess_token(), accessToken.getOpenid());
        if (!userInfo.isSuccess()) {
            throw new CommonServiceException(ApiResponseCode.WECHAT_AUTH_FAILURE);
        }

        // 通过 openid，获取用户信息
        User user = iUserService.getUserByOpenid(userInfo.getOpenid());
        if (Objects.isNull(user)) {
            throw new CommonServiceException(ApiResponseCode.WECHAT_AUTH_FAILURE);
        }

        return getLoginResponse(user, body.getSid(), body.getCid());
    }

    @Override
    @Transactional
    public LoginResponseVo wxLoginV2(WxLoginVo body) {

        log.info("------------------------------ 微信授权登录V2  ------------------------------");
        ApiResponseBody.printRequestParam(body);

        // 获取授权信息
        WeChatAppAccessTokenResponse accessToken = weChatApi.getAccessToken(body.getCode());
        if (!accessToken.isSuccess()) {
            throw new CommonServiceException(ApiResponseCode.WECHAT_AUTH_FAILURE);
        }

        // 获取微信用户信息
        WeChatAppUserInfoResponse userInfo = weChatApi.getUserInfo(accessToken.getAccess_token(), accessToken.getOpenid());
        if (!userInfo.isSuccess()) {
            throw new CommonServiceException(ApiResponseCode.WECHAT_AUTH_FAILURE);
        }

        // 登录信息
        LoginResponseVo loginResponseVo;

        // 通过 openid，获取用户信息
        User user = iUserService.getUserByOpenid(userInfo.getOpenid());
        if (Objects.isNull(user) ||
                (StringUtils.isEmpty(user.getMobile()) && StringUtils.isEmpty(user.getEmail()))) {
            // 存储 redis 缓存
            redisService.saveWxUserInfo(userInfo);

            loginResponseVo = LoginResponseVo.builder()
                    .openid(userInfo.getOpenid())
                    .build();
        } else {
            loginResponseVo = getLoginResponse(user, body.getSid(), body.getCid());
            if (StringUtils.isEmpty(loginResponseVo.getWxNickName())) {
                loginResponseVo.setWxNickName(userInfo.getNickname());
            }
        }
        return loginResponseVo;
    }

    @Override
    @Transactional
    public LoginResponseVo wxBind(WxBindVo body) {

        log.info("------------------------------ 微信绑定  ------------------------------");
        ApiResponseBody.printRequestParam(body);

        // 获取微信信息
        WeChatAppUserInfoResponse response = redisService.getWxUserInfo(body.getOpenid());
        if (Objects.isNull(response)) {
            throw new CommonServiceException(ApiResponseCode.WX_BIND_FAILURE);
        }

        // 验证验证码
        if (!redisService.verifyCode(body.getAccount(), body.getCaptcha())) {
            throw new CommonServiceException(ApiResponseCode.CAPTCHA_WRONG);
        }

        // 手机号，邮箱
        String mobile = "";
        String email = "";

        // 通过 openid 获取用户信息
        User user = iUserService.getUserByOpenid(body.getOpenid());

        // openId存在，绑定 新手机号/邮箱
        if (Objects.nonNull(user)) {
            // 已绑定过手机号/邮箱的，openid存在，不能再绑定新账号
            if (StringUtils.isNotEmpty(user.getMobile()) || StringUtils.isNotEmpty(user.getEmail())) {
                throw new CommonServiceException(ApiResponseCode.WX_BIND_ACCOUNT);
            }

            // 验证手机号/邮箱是否已注册，已注册不能绑定
            if (Objects.equals(AccountTypeEnum.EMAIL.getKey(), body.getAccountType())) {
                if (Objects.nonNull(iUserService.getUserByEmail(body.getAccount()))) {
                    throw new CommonServiceException(ApiResponseCode.EMAIL_REGISTER);
                }
                email = body.getAccount();
            } else {
                if (Objects.nonNull(iUserService.getUserByMobile(body.getAccount()))) {
                    throw new CommonServiceException(ApiResponseCode.MOBILE_REGISTER);
                }
                mobile = body.getAccount();
            }

            // 更新用户信息
            user = updateUser(user, user.getAccount(), mobile, email, body.getOpenid(),
                    response.getNickname(), response.getHeadimgurl());
        }
        // openId不存在，绑定 已有手机号/邮箱
        else {
            User userByAccount = null;
            // 验证手机号/邮箱是否已注册，未注册不能绑定
            if (Objects.equals(AccountTypeEnum.EMAIL.getKey(), body.getAccountType())) {
                userByAccount = iUserService.getUserByEmail(body.getAccount());
                if (Objects.isNull(userByAccount)) {
                    throw new CommonServiceException(ApiResponseCode.EMAIL_NOT_REGISTER);
                }
                email = body.getAccount();
            } else {
                userByAccount = iUserService.getUserByMobile(body.getAccount());
                if (Objects.isNull(userByAccount)) {
                    throw new CommonServiceException(ApiResponseCode.MOBILE_NOT_REGISTER);
                }
                mobile = body.getAccount();
            }

            // 更新用户信息
            user = updateUser(userByAccount, body.getAccount(), mobile, email, body.getOpenid(),
                    response.getNickname(), response.getHeadimgurl());
        }

        return getLoginResponse(user, body.getSid(), body.getCid());
    }

    @Override
    @Transactional
    public void wxUnbind(AuthInfo authInfo) {

        log.info("------------------------------ 微信解绑  ------------------------------");
        ApiResponseBody.printRequestParam(authInfo);

        // 验证用户是否存在
        User user = iUserService.getById(authInfo.getId());
        if (Objects.isNull(user)) {
            throw new CommonServiceException(ApiResponseCode.USER_NOT_EXIST);
        }

        // 更新用户信息
        user.setUpdatedAt(DateUtils.getSecondTimestamp());
        user.setOpenid("1");
        if (!iUserService.updateById(user)) {
            throw new CommonServiceException(ApiResponseCode.WX_UNBIND_FAILURE);
        }
    }

    @Override
    @Transactional
    public LoginResponseVo wxBind2(WxBind2Vo body, AuthInfo authInfo) {

        log.info("------------------------------ 微信绑定2  ------------------------------");
        ApiResponseBody.printRequestParam(body);

        // 获取授权信息
        WeChatAppAccessTokenResponse accessToken = weChatApi.getAccessToken(body.getCode());
        if (!accessToken.isSuccess()) {
            throw new CommonServiceException(ApiResponseCode.WECHAT_AUTH_FAILURE);
        }

        // 获取微信信息
        WeChatAppUserInfoResponse response = weChatApi.getUserInfo(accessToken.getAccess_token(), accessToken.getOpenid());
        if (Objects.isNull(response)) {
            throw new CommonServiceException(ApiResponseCode.WX_BIND_FAILURE);
        }

        // 验证登录用户是否已绑定微信
        User user = iUserService.getUserById(authInfo.getId());
        if (StringUtils.isNotEmpty(user.getOpenid()) && !Objects.equals("1", user.getOpenid())) {
            throw new CommonServiceException(ApiResponseCode.WX_BIND_ACCOUNT);
        }

        // 验证该微信是否已绑定
        if (Objects.nonNull(iUserService.getUserByOpenid(response.getOpenid()))) {
            throw new CommonServiceException(ApiResponseCode.WX_BIND_ACCOUNT);
        }

        // 获取登录用户信息
        user.setUpdatedAt(DateUtils.getSecondTimestamp());
        user.setOpenid(response.getOpenid());
        user.setWxNickname(response.getNickname());
        user.setAvatar(response.getHeadimgurl());
        if (!iUserService.updateById(user)) {
            throw new CommonServiceException(ApiResponseCode.WX_BIND_FAILURE);
        }

        return getLoginResponse(user, body.getSid(), body.getCid());
    }

    @Override
    public LoginResponseVo mobileEmailBind(MobileEmailBindVo body, AuthInfo authInfo) {

        log.info("------------------------------ 手机号/邮箱绑定  ------------------------------");
        ApiResponseBody.printRequestParam(body);

        // 验证验证码
        if (!redisService.verifyCode(body.getAccount(), body.getCaptcha())) {
            throw new CommonServiceException(ApiResponseCode.CAPTCHA_WRONG);
        }

        // 手机号，邮箱
        String mobile = "";
        String email = "";

        // 验证用户是否存在
        User user = iUserService.getById(authInfo.getId());
        if (Objects.isNull(user)) {
            throw new CommonServiceException(ApiResponseCode.USER_NOT_EXIST);
        }

        // 验证手机号/邮箱是否已注册，已注册不能绑定
        if (Objects.equals(AccountTypeEnum.EMAIL.getKey(), body.getAccountType())) {
            if (Objects.nonNull(iUserService.getUserByEmail(body.getAccount()))) {
                throw new CommonServiceException(ApiResponseCode.EMAIL_REGISTER);
            }
            // 验证用户是否已绑定邮箱
            if (StringUtils.isNotEmpty(user.getEmail())) {
                throw new CommonServiceException(ApiResponseCode.EMAIL_BIND);
            }
            email = body.getAccount();
        } else {
            if (Objects.nonNull(iUserService.getUserByMobile(body.getAccount()))) {
                throw new CommonServiceException(ApiResponseCode.MOBILE_REGISTER);
            }
            // 验证用户是否已绑定手机号
            if (StringUtils.isNotEmpty(user.getMobile())) {
                throw new CommonServiceException(ApiResponseCode.MOBILE_BIND);
            }
            mobile = body.getAccount();
        }

        // 更新用户信息
        user = updateUser(user, user.getAccount(), mobile, email, user.getOpenid(),
                user.getNickname(), user.getAvatar());

        return getLoginResponse(user, body.getSid(), body.getCid());
    }

    @Override
    public VersionVo firmwareUpdate(FirmwareUpdateVo body) {

        log.info("------------------------------ 固件升级  ------------------------------");
        ApiResponseBody.printRequestParam(body);

        // 判断版本号名称为空，提示"该设备需要返厂升级固件"
        if (Objects.isNull(body.getVersionName())) {
            throw new CommonServiceException(ApiResponseCode.FACTORY_UPGRADE_FIRMWARE);
        }

        // 获取最新版本信息
        Version version = versionService.getOne(body.getType(), body.getVersion());
        if (Objects.isNull(version) || version.getVersionName().equals(body.getVersionName())) {
            throw new CommonServiceException(ApiResponseCode.FIRMWARE_LATEST);
        }

        // 返回版本信息
        VersionVo versionVo = new VersionVo();
        versionVo.setFirmwareType(version.getFirmwareType());
        versionVo.setVersion(version.getVersion());
        versionVo.setVersionName(version.getVersionName());
        versionVo.setDownloadUrl(FileUtil.getUrl(version.getDownloadUrl(), configProperty.fileDomain));
        return versionVo;
    }

}
